// 13.1 名称的分类
// 在C++模板中，名称的处理是一个复杂而重要的话题。第13.1节主要讨论了模板中名称的分类，这对理解模板的编译和实例化过程至关重要。

// 依赖名称与非依赖名称
// 在模板中，名称可以分为两大类：
// 1.非依赖名称 (Non-dependent names)
//      不依赖于模板参数的名称
//      在模板解析阶段就能确定其含义
//      在模板定义时就会被解析
// 2.依赖名称 (Dependent names)
//      依赖于模板参数的名称
//      只有在模板实例化时才能确定其含义
//      解析推迟到模板实例化阶段

// 示例分析
template <typename T>
class MyClass
{
public:
    void foo()
    {
        std::cout << "Hello";    // 非依赖名称：std::cout
        T::value_type x;         // 依赖名称：T::value_type
        typename T::iterator it; // 依赖名称：T::iterator
        int n = sizeof(T);       // 依赖表达式
    }
};
// 在这个例子中：
// -std::cout 是非依赖名称，因为它不依赖于模板参数T
// -T::value_type 和 T::iterator 是依赖名称，因为它们依赖于模板参数T
// -sizeof(T) 是依赖表达式，因为其结果依赖于模板参数T

// 依赖名称的类型
// 依赖名称可以进一步分类为：
// 1.类型依赖名称 (Type-dependent names)
//      表示一个类型，依赖于模板参数
//      需要使用 typename 关键字明确指出它是一个类型
//      例如：typename T::value_type

// 2.值依赖名称 (Value-dependent names)
//      表示一个值，依赖于模板参数
//      例如：T::value、array[sizeof(T)]

// 3.模板依赖名称 (Template-dependent names)
//      表示一个模板，依赖于模板参数
//      需要使用 template 关键字
//      例如：T::template rebind<U>

// 两阶段查找 (Two-phase lookup)
// C++模板的名称解析采用两阶段查找机制：
// 1.第一阶段（模板定义时）
//      解析非依赖名称
//      检查模板语法是否正确
//      验证非依赖名称是否有效
// 2.第二阶段（模板实例化时）SFIANE
//      解析依赖名称
//      验证整个模板实例是否有效

// 依赖名称解析的挑战
// 依赖名称解析面临的主要挑战：
// 1.歧义性：依赖名称可能是类型、值或模板
// 2.上下文依赖：名称的含义可能依赖于模板参数的实际类型
// 3.延迟解析：编译器必须推迟某些名称的解析

// 解决依赖名称歧义的关键字
// 1.typename 关键字
//      用于指明依赖名称是一个类型
//      例如：typename T::iterator it;
// 2.template 关键字
//      用于指明依赖名称是一个模板
//      例如：T::template rebind<U>::other

// 实际应用示例
template <typename Container>
void printFirstElement(const Container &c)
{
    // 使用typename指明这是一个类型
    typename Container::const_iterator it = c.begin();

    if (it != c.end())
    {
        // 使用typename指明这是一个类型
        typename Container::value_type value = *it;
        std::cout << value << std::endl;
    }
}

class ModelInference
{
public:
    // 推理结果类
    class Result
    {
    public:
        // 支持多种可能的数据类型
        enum class DataType
        {
            FLOAT32,
            FLOAT16,
            INT8,
            UNKNOWN
        };

        // 构造函数，根据实际数据创建结果
        template <typename T>
        Result(const T *data, int width, int height, int channels)
        {
            // 存储元数据
            width_ = width;
            height_ = height;
            channels_ = channels;

            // 确定数据类型
            if constexpr (std::is_same_v<T, float>)
            {
                type_ = DataType::FLOAT32;
            }
            else if constexpr (std::is_same_v<T, half> || std::is_same_v<T, __half>)
            {
                type_ = DataType::FLOAT16;
            }
            else if constexpr (std::is_same_v<T, int8_t>)
            {
                type_ = DataType::INT8;
            }
            else
            {
                type_ = DataType::UNKNOWN;
            }

            // 复制数据
            size_t dataSize = width * height * channels * sizeof(T);
            data_.resize(dataSize);
            std::memcpy(data_.data(), data, dataSize);
        }

        // 转换为cv::Mat
        cv::Mat toCVMat() const
        {
            cv::Mat result;

            switch (type_)
            {
            case DataType::FLOAT32:
                result = createMat<float>();
                break;
            case DataType::FLOAT16:
                // 需要从FP16转换到FP32
                result = convertFP16ToCVMat();
                break;
            case DataType::INT8:
                result = createMat<int8_t>();
                break;
            default:
                throw std::runtime_error("Unknown data type");
            }

            return result;
        }

    private:
        int width_ = 0;
        int height_ = 0;
        int channels_ = 0;
        DataType type_ = DataType::UNKNOWN;
        std::vector<uint8_t> data_; // 原始字节数据

        // 创建特定类型的cv::Mat
        template <typename T>
        cv::Mat createMat() const
        {
            int type;
            if constexpr (std::is_same_v<T, float>)
            {
                type = CV_32FC(channels_);
            }
            else if constexpr (std::is_same_v<T, int8_t>)
            {
                type = CV_8SC(channels_);
            }
            else
            {
                throw std::runtime_error("Unsupported type for cv::Mat");
            }

            cv::Mat result(height_, width_, type);
            std::memcpy(result.data, data_.data(), data_.size());
            return result;
        }

        // 特殊处理FP16到cv::Mat的转换
        cv::Mat convertFP16ToCVMat() const
        {
            // 假设data_中存储的是FP16数据
            const uint16_t *fp16Data = reinterpret_cast<const uint16_t *>(data_.data());
            size_t numElements = width_ * height_ * channels_;

            // 创建FP32 Mat
            cv::Mat result(height_, width_, CV_32FC(channels_));
            float *fp32Data = reinterpret_cast<float *>(result.data);

            // 转换FP16到FP32
            for (size_t i = 0; i < numElements; ++i)
            {
                fp32Data[i] = convertHalfToFloat(fp16Data[i]);
            }

            return result;
        }

        // FP16到FP32的转换函数
        float convertHalfToFloat(uint16_t half) const
        {
            // 实现FP16到FP32的转换
            // 这里是简化实现，实际应使用标准库或SIMD指令
            int sign = ((half >> 15) & 1);
            int exp = ((half >> 10) & 0x1F);
            int mantissa = (half & 0x3FF);

            if (exp == 0)
            {
                if (mantissa == 0)
                    return sign ? -0.0f : 0.0f;
                float result = mantissa / 1024.0f;
                return sign ? -result : result;
            }

            if (exp == 31)
            {
                if (mantissa == 0)
                    return sign ? -INFINITY : INFINITY;
                return NAN;
            }

            float result = (1.0f + mantissa / 1024.0f) * std::pow(2.0f, exp - 15);
            return sign ? -result : result;
        }
    };

    // 执行推理并返回结果
    template <typename ModelT>
    Result infer(ModelT &model, const cv::Mat &input)
    {
        // 执行模型推理
        auto output = model.forward(input);

        // 根据模型输出类型创建Result
        using OutputType = typename decltype(output)::value_type;
        return Result(output.data(), output.width(), output.height(), output.channels());
    }
};

// 使用示例
void processImage(const cv::Mat &image)
{
    // 加载模型（运行时确定类型）
    auto model = loadModelBasedOnFile("model.weights");

    // 创建推理引擎
    ModelInference engine;

    // 执行推理
    auto result = engine.infer(model, image);

    // 获取cv::Mat格式的结果
    cv::Mat outputMat = result.toCVMat();

    // 后续处理...
    cv::imshow("Result", outputMat);
    cv::waitKey(0);
}